package org.zjx.window.window;

import com.sun.jna.platform.win32.WinDef;
import lombok.Getter;
import org.zjx.window.window.impl.GameWindow;
import org.zjx.window.window.impl.LoginWindow;
import org.zjx.window.window.impl.OpenWindow;
import org.zjx.window.window.impl.StartWindow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 窗口管理器
 * 负责维护指定数量的游戏窗口，自动处理窗口的创建、销毁和状态转换
 *
 * @author zjx
 * @since 1.0
 */
public class WindowManager {

    /**
     * 管理的窗口列表
     */
    private final List<IWindow> managedWindows;

    /**
     * 目标窗口数量
     * -- GETTER --
     *  获取目标窗口数量
     */
    @Getter
    private final int targetWindowCount;

    /**
     * 游戏可执行文件路径
     */
    private final String gameExePath;

    /**
     * 调度执行器，用于定期检查窗口状态
     */
    private final ScheduledExecutorService scheduler;

    /**
     * 运行状态标志
     */
    @Getter
    private volatile boolean running = false;

    /**
     * 检查间隔（毫秒）
     */
    private static final long CHECK_INTERVAL_MS = 2000;

    /**
     * 构造方法
     *
     * @param targetWindowCount 目标窗口数量
     * @param gameExePath 游戏可执行文件路径
     * @throws IllegalArgumentException 如果targetWindowCount小于1或gameExePath为null/空
     */
    public WindowManager(int targetWindowCount, String gameExePath) {
        if (targetWindowCount < 1) {
            throw new IllegalArgumentException("目标窗口数量必须大于0: " + targetWindowCount);
        }
        if (gameExePath == null || gameExePath.trim().isEmpty()) {
            throw new IllegalArgumentException("游戏可执行文件路径不能为空");
        }

        this.targetWindowCount = targetWindowCount;
        this.gameExePath = gameExePath.trim();
        this.managedWindows = new CopyOnWriteArrayList<>();
        this.scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread t = new Thread(r, "window-manager-scheduler");
            t.setDaemon(true);
            return t;
        });
    }

    /**
     * 启动窗口管理器
     */
    public void start() {
        if (running) {
            return;
        }

        running = true;
        System.out.println("启动窗口管理器，目标窗口数量: " + targetWindowCount);

        // 立即执行一次初始检查
        checkWindows();

        // 定期执行窗口检查
        scheduler.scheduleWithFixedDelay(this::checkWindows,
                CHECK_INTERVAL_MS, CHECK_INTERVAL_MS, TimeUnit.MILLISECONDS);
    }

    /**
     * 停止窗口管理器
     */
    public void stop() {
        if (!running) {
            return;
        }

        running = false;
        System.out.println("停止窗口管理器");

        // 关闭调度器
        scheduler.shutdown();
        try {
            if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            scheduler.shutdownNow();
            Thread.currentThread().interrupt();
        }

        // 关闭所有管理的窗口
        for (IWindow window : managedWindows) {
            try {
                window.shutdown();
            } catch (Exception e) {
                System.err.println("关闭窗口失败: " + window.getName() + " - " + e.getMessage());
            }
        }
        managedWindows.clear();
    }

    /**
     * 检查窗口状态并执行必要的管理操作
     */
    private void checkWindows() {
        if (!running) {
            return;
        }

        try {
            // 1. 移除已失效的窗口
            removeInvalidWindows();

            // 2. 发现并添加新的窗口
            discoverAndAddNewWindows();

            // 3. 检查是否需要创建新窗口
            checkAndCreateNewWindows();

            // 打印当前状态
            logCurrentStatus();

        } catch (Exception e) {
            System.err.println("窗口检查异常: " + e.getMessage());
        }
    }

    /**
     * 移除已失效的窗口
     */
    private void removeInvalidWindows() {
        // 使用流式处理来收集需要移除的窗口
        List<IWindow> windowsToRemove = managedWindows.stream()
                .filter(window -> !isWindowValid(window))
                .collect(Collectors.toList());

        // 移除无效窗口
        for (IWindow window : windowsToRemove) {
            System.out.println("移除失效窗口: " + window.getName() + " - " + window.getTitle());
            try {
                window.shutdown();
            } catch (Exception e) {
                System.err.println("关闭失效窗口异常: " + e.getMessage());
            }
            managedWindows.remove(window);
        }
    }

    /**
     * 检查窗口是否有效
     *
     * @param window 要检查的窗口
     * @return 如果窗口有效返回true，否则返回false
     */
    private boolean isWindowValid(IWindow window) {
        if (window == null) {
            return false;
        }

        // OpenWindow 特殊处理
        if (window instanceof OpenWindow) {
            return window.isExists();
        }

        // 其他窗口检查存在性和有效性
        return window.isExists() && window.isValid();
    }

    /**
     * 发现并添加新的窗口
     */
    private void discoverAndAddNewWindows() {
        // 获取所有可用的窗口句柄
        Set<WinDef.HWND> existingHwnds = getManagedWindowHwnds();

        // 检查各种类型的窗口
        addNewWindowsOfType(GameWindow.getWindows(), GameWindow.class, existingHwnds);
        addNewWindowsOfType(LoginWindow.getWindows(), LoginWindow.class, existingHwnds);
        addNewWindowsOfType(StartWindow.getWindows(), StartWindow.class, existingHwnds);
    }

    /**
     * 添加特定类型的新窗口
     *
     * @param hwndList 窗口句柄列表
     * @param windowClass 窗口类型
     * @param existingHwnds 已管理的窗口句柄集合
     */
    private void addNewWindowsOfType(List<WinDef.HWND> hwndList, Class<?> windowClass,
                                     Set<WinDef.HWND> existingHwnds) {
        for (WinDef.HWND hwnd : hwndList) {
            if (!existingHwnds.contains(hwnd)) {
                try {
                    IWindow newWindow = createWindowByType(windowClass, hwnd);
                    if (newWindow != null) {
                        managedWindows.add(newWindow);
                        System.out.println("发现新窗口: " + newWindow.getName() + " - " + newWindow.getTitle());
                    }
                } catch (Exception e) {
                    System.err.println("创建窗口失败 [" + windowClass.getSimpleName() + "]: " + e.getMessage());
                }
            }
        }
    }

    /**
     * 根据类型创建窗口实例
     *
     * @param windowClass 窗口类型
     * @param hwnd 窗口句柄
     * @return 窗口实例，创建失败返回null
     */
    private IWindow createWindowByType(Class<?> windowClass, WinDef.HWND hwnd) {
        try {
            if (windowClass == GameWindow.class) {
                return new GameWindow(hwnd);
            } else if (windowClass == LoginWindow.class) {
                return new LoginWindow(hwnd);
            } else if (windowClass == StartWindow.class) {
                return new StartWindow(hwnd);
            }
        } catch (Exception e) {
            System.err.println("创建窗口实例失败: " + e.getMessage());
        }
        return null;
    }

    /**
     * 检查并创建新窗口
     */
    private void checkAndCreateNewWindows() {
        int currentValidCount = getValidWindowCount();

        if (currentValidCount < targetWindowCount && !hasOpenOrStartWindow()) {
            System.out.println("窗口数量不足 (" + currentValidCount + "/" + targetWindowCount + ")，创建新OpenWindow");
            createOpenWindow();
        }
    }

    /**
     * 获取有效窗口数量（不包括OpenWindow）
     *
     * @return 有效窗口数量
     */
    private int getValidWindowCount() {
        return (int) managedWindows.stream()
                .filter(window -> !(window instanceof OpenWindow))
                .filter(this::isWindowValid)
                .count();
    }

    /**
     * 检查是否存在OpenWindow或StartWindow
     *
     * @return 如果存在返回true，否则返回false
     */
    private boolean hasOpenOrStartWindow() {
        return managedWindows.stream()
                .anyMatch(window -> (window instanceof OpenWindow || window instanceof StartWindow)
                        && isWindowValid(window));
    }

    /**
     * 创建OpenWindow
     */
    private void createOpenWindow() {
        try {
            OpenWindow openWindow = new OpenWindow(gameExePath);
            managedWindows.add(openWindow);
            System.out.println("创建OpenWindow: " + openWindow.getName());
        } catch (Exception e) {
            System.err.println("创建OpenWindow失败: " + e.getMessage());
        }
    }

    /**
     * 获取已管理窗口的句柄集合
     *
     * @return 窗口句柄集合
     */
    private Set<WinDef.HWND> getManagedWindowHwnds() {
        return managedWindows.stream()
                .map(IWindow::getHwnd)
                .collect(Collectors.toSet());
    }

    /**
     * 获取所有管理的窗口
     *
     * @return 窗口列表（不可修改的视图）
     */
    public List<IWindow> getManagedWindows() {
        return Collections.unmodifiableList(new ArrayList<>(managedWindows));
    }

    /**
     * 获取游戏窗口列表
     *
     * @return 游戏窗口列表
     */
    public List<GameWindow> getGameWindows() {
        return managedWindows.stream()
                .filter(window -> window instanceof GameWindow)
                .filter(this::isWindowValid)
                .map(window -> (GameWindow) window)
                .collect(Collectors.toList());
    }

    /**
     * 获取有效窗口数量
     *
     * @return 有效窗口数量
     */
    public int getCurrentWindowCount() {
        return getValidWindowCount();
    }

    /**
     * 记录当前状态
     */
    private void logCurrentStatus() {
        int gameCount = (int) managedWindows.stream().filter(w -> w instanceof GameWindow).count();
        int loginCount = (int) managedWindows.stream().filter(w -> w instanceof LoginWindow).count();
        int startCount = (int) managedWindows.stream().filter(w -> w instanceof StartWindow).count();
        int openCount = (int) managedWindows.stream().filter(w -> w instanceof OpenWindow).count();
        int validCount = getValidWindowCount();

        System.out.printf("窗口状态: 游戏=%d, 登录=%d, 启动=%d, 打开=%d, 有效=%d/%d%n",
                gameCount, loginCount, startCount, openCount, validCount, targetWindowCount);
    }

    /**
     * 等待所有窗口就绪（阻塞直到达到目标数量或超时）
     *
     * @param timeout 超时时间
     * @param unit 时间单位
     * @return 如果在超时前就绪返回true，否则返回false
     * @throws InterruptedException 如果等待过程中被中断
     */
    public boolean waitForWindowsReady(long timeout, TimeUnit unit) throws InterruptedException {
        long endTime = System.currentTimeMillis() + unit.toMillis(timeout);

        while (System.currentTimeMillis() < endTime) {
            if (getValidWindowCount() >= targetWindowCount) {
                return true;
            }
            Thread.sleep(1000);
        }

        return getValidWindowCount() >= targetWindowCount;
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (running) {
                stop();
            }
        } finally {
            super.finalize();
        }
    }
}